package com.easipass.framework.eirframeworkcoredsl;

class Tokenizer extends AbstractTokenizer {

    Tokenizer() {
    }

    protected void process() {
        boolean justProcessedEquals = false;
        while (pos < max) {
            char ch = toProcess[pos];

            if (justProcessedEquals) {
                if (!isWhitespace(ch) && ch != 0) {
                    if (isArgValueIdentifierTerminator(ch, false)) {
                        raiseException(DSLMessage.EXPECTED_ARGUMENT_VALUE, ch);
                    }
                    lexArgValueIdentifier();
                }
                justProcessedEquals = false;
                continue;
            }

            if (isAlphabetic(ch) || isDigit(ch) || ch == '_' || ch == '$') {
                lexIdentifier();
            } else {
                switch (ch) {
                    case '-':
                        if (isTwoCharToken(TokenKind.DOUBLE_MINUS)) {
                            pushPairToken(TokenKind.DOUBLE_MINUS);
                        } else if (isTwoCharToken(TokenKind.ARROW)) {
                            pushPairToken(TokenKind.ARROW);
                        } else {
                            throw new ParseException(expressionString, pos, DSLMessage.MISSING_CHARACTER, "-");
                        }
                        break;
                    case '=':
                        justProcessedEquals = true;
                        pushCharToken(TokenKind.EQUALS);
                        break;
                    case '&':
                        if (isTwoCharToken(TokenKind.ANDAND)) {
                            pushPairToken(TokenKind.ANDAND);
                        } else if(isCharToken(TokenKind.AND)){
                            pushCharToken(TokenKind.AND);
                        }else{
                            raiseException(DSLMessage.SERVICE_DOUBLE_AND_REQUIRED);
                        }
                        break;
                    case '|':
                        if (isTwoCharToken(TokenKind.DOUBLEPIPE)) {
                            pushPairToken(TokenKind.DOUBLEPIPE);
                        } else if(isCharToken(TokenKind.PIPE)){
                            pushCharToken(TokenKind.PIPE);
                        }else{
                            raiseException(DSLMessage.SERVICE_DOUBLE_OR_REQUIRED);
                        }
                        break;
                    case ' ':
                    case '\t':
                    case '\r':
                        pos++;
                        break;
                    case '\n':
                        addLinebreak();
                        break;
                    case '.':
                        pushCharToken(TokenKind.DOT);
                        break;
                    case '<':
                        pushCharToken(TokenKind.LT);
                        break;
                    case '>':
                        pushCharToken(TokenKind.GT);
                        break;
                    case ':':
                        pushCharToken(TokenKind.COLON);
                        break;
                    case '(':
                        pushCharToken(TokenKind.OPEN_PAREN);
                        break;
                    case ')':
                        pushCharToken(TokenKind.CLOSE_PAREN);
                        break;
                    case '/':
                        pushCharToken(TokenKind.SLASH);
                        break;
                    case '#':
                        pushCharToken(TokenKind.HASH);
                        break;
                    case '*':
                        pushCharToken(TokenKind.STAR);
                        break;
                    case ';':
                        pushCharToken(TokenKind.SEMICOLON);
                        break;
                    case '\'':
                        lexQuotedStringLiteral();
                        break;
                    case '"':
                        lexDoubleQuotedStringLiteral();
                        break;
                    case '@':
                        pushCharToken(TokenKind.REFERENCE);
                        break;
                    case 0:
                        pos++;
                        break;
                    case '\\':
                        throw new ParseException(expressionString, pos, DSLMessage.UNEXPECTED_ESCAPE_CHAR);
                    default:
                        throw new ParseException(expressionString, pos, DSLMessage.UNEXPECTED_DATA,
                                Character.valueOf(ch).toString());
                }
            }
        }
    }

    @Override
    public String toString() {
        StringBuilder s = new StringBuilder();
        s.append(this.expressionString).append("\n");
        for (int i = 0; i < this.pos; i++) {
            s.append(" ");
        }
        s.append("^\n");
        s.append(tokens).append("\n");
        return s.toString();
    }

    protected void addLinebreak() {
        int[] newLinebreaks = new int[linebreaks.length + 1];
        System.arraycopy(linebreaks, 0, newLinebreaks, 0, linebreaks.length);
        newLinebreaks[linebreaks.length] = pos;
        linebreaks = newLinebreaks;
        pos++;
    }
}
